#ifndef PILHADSE_HPP_
#define PILHADSE_HPP_

#include "./../includes/no.hpp"

template <class T>
class pilhaDSE
{
	
public:
	
	pilhaDSE();

	pilhaDSE(const pilhaDSE<T>&);

	~pilhaDSE();

	void
	push( const T& );

	void
	pop();

	T
	getInfo();
	
	void
	setInfo( const T& );

	void
	clear();

	bool
	isEmpty();

	pilhaDSE<T>&
	operator= ( const pilhaDSE<T>& );
	
protected:

	void
	copy( const pilhaDSE<T>& );

	noh<T>*
	cursor;

};

/********************
 * 					*
 * 	Implementa��o	*
 * 					*
 ********************/


template <class T>
pilhaDSE<T>::pilhaDSE()
{
	this->cursor = 0;
}

template <class T>
pilhaDSE<T>::pilhaDSE(const pilhaDSE<T>& _toCopy)
{
	this->cursor = 0;

	this->copy( _toCopy );
}

template <class T>
pilhaDSE<T>::~pilhaDSE()
{
	this->clear();
}

template <class T> void
pilhaDSE<T>::push(const T& _info)
{
	noh<T>*
	newNoh = new noh<T>(_info);
	
	if (this->cursor == 0)
	{
		this->cursor= newNoh;
	}
	else
	{
		newNoh->setAnterior( this->cursor );
		
		this->cursor = newNoh;
	}
}

template <class T> void
pilhaDSE<T>::pop()
{
	if (! this->isEmpty() )
	{
		if (this->cursor->getAnterior() == 0)
		{
			delete this->cursor;
			this->cursor = 0;
		}
		else
		{
			noh<T>*
			temp = this->cursor;
			
			this->cursor = this->cursor->getAnterior();
			
			delete temp;
		}
	}
	else
	{
		const std::string
		message = "ops... trying to pop an empty stack";

		error*
		e = new error(message);
	
		throw e;
	}
}

template <class T> T
pilhaDSE<T>::getInfo()
{
	if (! this->isEmpty())
	{
		return this->cursor->getInfo();
	}
	
	const std::string
	message = "ops... trying to retrieve from an empty stack!";

	error* 
	e = new error(message);

	throw e;
}

template <class T> void
pilhaDSE<T>::setInfo( const T& _info )
{
	if (! this->isEmpty())
	{
		this->cursor->setInfo( _info );
	}
	else
	{
		const std::string
		message = "ops... trying to alter an empty stack!";
	
		error* 
		e = new error(message);
	
		throw e;
	}
}

template <class T> void
pilhaDSE<T>::clear()
{
	while (! this->isEmpty())
	{
		this->pop();
	}
	this->cursor = 0;
}

template <class T> bool
pilhaDSE<T>::isEmpty()
{
	if (this->cursor != 0)
	{
		return false;
	}
	else
	{
		return true;
	}
}

template<class T> pilhaDSE<T>&
pilhaDSE<T>::operator= ( const pilhaDSE<T>& _toEqualize )
{
	delete this->cursor;
	this->cursor = 0;
	
	this->copy(_toEqualize);
	
	return *this;
}

/********************************
 * 								*
 *		Protected methods		*
 * 								*
 ********************************/

template <class T> void
pilhaDSE<T>::copy( const pilhaDSE<T>& _toCopy)
{
	noh<T>*
	toCopyCursor = _toCopy.cursor;
		
	noh<T>*
	CursorOriginalPosition = toCopyCursor;
	
	if ( toCopyCursor->getAnterior() == 0 )
	{
		while ( toCopyCursor != 0 )
		{
			noh<T>*
			temp = new noh<T>;

			temp->setInfo( toCopyCursor->getInfo() );

			if (this->cursor == 0)
			{
				this->cursor = temp;
			}
			else
			{
				temp->setAnterior( this->cursor );
			}
			toCopyCursor = toCopyCursor->getPosterior();
		}		

	}
	this->cursor = CursorOriginalPosition;
}

#endif /*PILHADSE_HPP_*/
